package com.bayesianWeka;

import weka.classifiers.AbstractClassifier;
import weka.core.Instance;
import weka.core.Instances;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author: Decade
 * @Date: 2021/3/30 17:48
 * 地理学院项目的推理实验
 */
public class JiLinWater extends AbstractClassifier {

    private int m_NumClasses;

    private int m_NumAttributes;

    private List<Integer>[] lists;

    private CommonUtils commonUtils;

    @Override
    public void buildClassifier(Instances instances) throws Exception{

        //目前设想的代码结构如下：
        //搞一个list[]数组 这个数组用于存放
        commonUtils = new CommonUtils(instances);
        m_NumClasses = commonUtils.getM_NumClasses();
        m_NumAttributes = commonUtils.getM_NumAttributes();

        lists = new List[m_NumAttributes - 1];

        //给lists申请空间
        for (int i = 0; i < m_NumAttributes - 1; i++) {
            lists[i] = new ArrayList<>();
        }

        //这个模型需要去计算F(XXX) 和 F(XXXX)
        commonUtils.Count3XAnd4X();

        //计算H(x|x)  H(x|xx) 和 H(x|xxx)
        double[][] xxEntropyInf = commonUtils.getXXEntropyInf();
        double[][][] xxxEntropyInf = commonUtils.getXXXEntropyInf();
        double[][][][] xxxxEntropyInf = commonUtils.getXXXXEntropyInf();

        //接着就是把原始地理拓扑图的结构初始化进来就行
        lists[0].add(3);
        lists[1].add(0);
        lists[1].add(2);
        lists[1].add(6);
        lists[3].add(5);
        lists[6].add(4);
        lists[6].add(7);
        lists[6].add(8);

        //不需要考虑技术含量的问题！ 只需要考虑怎么去把需求实现了！
        //然后考虑是否可以增加弧 手动去操作 从5到0 看看能不能增加个弧 （显然是可以的 我猜的）
        //再考虑 能否删弧 0->1 2->1 6->1 7->6 8->6 4->6 这6条弧能不能删一删

        /* 删弧的过程和增弧的过程值得商榷  到底该怎么去计算依赖关系呢
        *  比如7 8 4 6 我们究竟是使用H(x6|x4,x7,x8)呢  还是说可以  H(x6|x4) + H(x6|x7) + H(x6|x8)计算呢  还是说有其他更好的方法去衡量呢？
        *  2021.03.30留
        *  */

        /* 拟加弧操作 事实证明这个if肯定进得去 所以没啥太大意义 */
//        if (xxxEntropyInf[0][3][5] < xxEntropyInf[0][3]){
//            lists[0].add(5);
//        }

        /* 拟删弧操作 事实证明三阶的熵肯定是小于二阶的熵  所以其实也没啥太大意义 */
        /* 所以 怎么去寻找意义呢？
        *  大致只能使用独立性验证的角度来弄了
        *  */
//        double xxxxEntropy = xxxxEntropyInf[6][4][7][8];
//        if (xxxEntropyInf[6][7][8] < xxxxEntropy){
//            lists[6].remove(4);
//        } else if (xxxEntropyInf[6][4][8] < xxxxEntropy){
//            lists[6].remove(7);
//        } else if (xxxEntropyInf[6][7][4] < xxxxEntropy){
//            lists[6].remove(8);
//        }

//        System.out.println("xxEntropyInf[0][3] = " + xxEntropyInf[0][3]);
//        System.out.println("xxxEntropyInf[0][3][5] = " + xxxEntropyInf[0][3][5]);
//
//        System.out.println("xxEntropyInf[1][0] = " + xxEntropyInf[1][0]);
//        System.out.println("xxxEntropyInf[1][3][0] = " + xxxEntropyInf[1][3][0]);
//
//        System.out.println("xxxxEntropyInf[6][4][7][8] = " + xxxxEntropyInf[6][4][7][8]);
//        System.out.println("xxxEntropyInf[6][7][8] = " + xxxEntropyInf[6][7][8]);
//        System.out.println("xxxEntropyInf[6][4][8] = " + xxxEntropyInf[6][4][8]);
//        System.out.println("xxxEntropyInf[6][7][4] = " + xxxEntropyInf[6][7][4]);
//
//        System.out.println("xxxxEntropyInf[1][0][2][6] = " + xxxxEntropyInf[1][0][2][6]);
//        System.out.println("xxxEntropyInf[1][0][2] = " + xxxEntropyInf[1][0][2]);
//        System.out.println("xxxEntropyInf[1][0][6] = " + xxxEntropyInf[1][0][6]);
//        System.out.println("xxxEntropyInf[1][2][6] = " + xxxEntropyInf[1][2][6]);
        //最后要验证 拓扑结构的对数似然 log(P(x0,x1,x2,...,x8))

    }

    public double[] distributionForInstance(Instance instance) throws Exception{

        //联合概率P(x0,...,x8) = P(...) 反正按拓扑结构来就完事儿了
        double jointP = commonUtils.P_xxx(instance,0,3,5) * commonUtils.P_xxxx(instance, 1,0,2,6)
                        * commonUtils.P(instance,2) * commonUtils.P_xx(instance,3,5) * commonUtils.P(instance,4)
                        * commonUtils.P(instance,5) * commonUtils.P_xxx(instance,6,4,8) * commonUtils.P(instance,7)
                        * commonUtils.P(instance,8);
        double logLikeliHood = Math.log(jointP) / Math.log(2);
        System.out.println(logLikeliHood);
        return new double[]{1.0,2.0};
    }

    public static void main(String[] args) {
        runClassifier(new JiLinWater(), args);
    }
}
